package com.luzh.myspring.beans.factory.support;

import com.luzh.myspring.beans.BeanException;
import com.luzh.myspring.beans.factory.DisposableBean;
import com.luzh.myspring.beans.factory.ObjectFactory;
import com.luzh.myspring.beans.factory.config.SingletonBeanRegistry;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 单例注册表（销毁bean）
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    // 一级缓存，存放完整单例对象的容器
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    // 二级缓存，存放没有完全实例化的对象
    protected final Map<String, Object> earlySingletonObjects = new HashMap<>();
    // 三级缓存，存放匿名工厂
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

    //存放需要销毁的bean的容器
    private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();
    //空对象
    protected static final Object NULL_OBJECT = new Object();


    @Override
    public Object getSingleton(String beanName) {
        //查询一级缓存
        Object singletonObject = singletonObjects.get(beanName);
        if (null == singletonObject) {
            singletonObject = earlySingletonObjects.get(beanName);
            //查询二级缓存
            if (null == singletonObject) {
                ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    //从匿名工厂获取对象
                    singletonObject = singletonFactory.getObject();
                    //把三级缓存中的真实对象获取出来，放入二级缓存中
                    earlySingletonObjects.put(beanName, singletonObject);
                    singletonFactories.remove(beanName);
                }
            }
        }
        return singletonObject;
    }

    /**
     * 注册完整单例，删除二三级缓存
     * @param beanName
     * @param singletonObject
     */
    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
        earlySingletonObjects.remove(beanName);
        singletonFactories.remove(beanName);
    }

    /**
     * 注册匿名单例工厂
     * @param beanName
     * @param singletonFactory
     */
    protected void registerSingletonFactory(String beanName, ObjectFactory<?> singletonFactory){
        //一级缓存中存在则无需注册
        if (!this.singletonObjects.containsKey(beanName)) {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);//
        }
    }

    public void registerDisposableBean(String beanName, DisposableBean bean) {
        disposableBeans.put(beanName, bean);
    }

    /**
     * 销毁所有可销毁bean
     */
    public void destroySingletons() {
        String[] disposableBeanNames = disposableBeans.keySet().toArray(new String[0]);
        //倒序销毁
        for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
            String beanName = disposableBeanNames[i];
            DisposableBean disposableBean = disposableBeans.remove(beanName);
            try {
                disposableBean.destroy();
            } catch (Exception e) {
                throw new BeanException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
            }
        }
    }
}
